/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#ifndef IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_NODE_INTERNAL_H
#define IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_NODE_INTERNAL_H

#include "imageknife_node.h"
#include "arkui_node.h"
#include "request/imageknife_request_internal.h"
#include "image_data_cache_internal.h"
#include "imageknife_trace.h"
#include "imageknife_task_internal.h"
#include <cstdint>
#include <list>

namespace ImageKnifePro {

class ImageKnifeNodeInternal : public ImageKnifeNode, public ArkUINode {
public:
    enum NodeState {
        AVAILABLE,
        CLEARED
    };

    ImageKnifeNodeInternal(std::shared_ptr<ImageKnifeOption> option,
                           ArkUI_NodeHandle handle, bool customMeasure = false);

    ~ImageKnifeNodeInternal() override;

    // ArkTs 用法需要记录组件id
    void SetComponentId(std::string componentId)
    {
        IMAGE_KNIFE_CHECK(imageKnifeRequest_ == nullptr);
        if (componentId_.empty()) {
            ImageKnifeTrace trace("SetComponentId", componentId);
            trace.StartSyncTrace();
            IMAGE_KNIFE_LOG(LOG_DEBUG, "[ID:%{public}s] ImageNode Created, Animator Node:%{public}d",
                            componentId.c_str(), IsAnimator());
        }
        componentId_ = componentId;
        imageKnifeRequest_->SetComponentId(componentId);
    }

    std::string GetComponentId() const
    {
        return componentId_;
    }

    virtual bool IsAnimator() const = 0;

    // 必需在主线程中运行
    virtual bool Display(std::shared_ptr<ImageDataCacheInternal> data, bool isMainSrc) = 0;

    virtual void TerminateAnimation()
    {
    }

    virtual void FitImage(int fitEnum)
    {
    }

    void UpdateAnimatorOption(std::shared_ptr<AnimatorOption> option) override
    {
    }

    /**
     * @brief 更新图片，根据主图key是否发生变化来判断是否需要重新加载
     * 主图key没有变换时:
     * 1. 图片正在加载中，继续加载但组件属性可能发生变换需要更新，记录最新属性状态，加载完成后应用
     * 2. 已加载完毕，对变换的属性状态立即进行更新
     * 3. 加载失败或取消，图片并未显示， 进行重新加载
     * 多线程竞争：不涉及。Update，Apply，Display均在主线程
     * @param option 图片加载参数描述对象
     */
    void Update(std::shared_ptr<ImageKnifeOption> option) override;

    // 组件应用最新的属性设置
    void ApplyAttribute(ImageRequestType type);

    void DisposeNode() override;

    void SyncLoad(bool syncLoad) override;

    void Execute() override;

    void Adaptable(bool adaptable) override;

    void ContentTransition(ContentTransitionType effectType) override;

    void Reuse()
    {
        componentVersion_++;
        nodeState_ = AVAILABLE;
    }

    void Clear() override
    {
        nodeState_ = CLEARED;
        TerminateAnimation();
        RemoveDisplayedImage();
    }

    std::shared_ptr<ImageKnifeRequest> GetImageKnifeRequest() const override
    {
        return imageKnifeRequest_;
    }

    std::shared_ptr<ImageKnifeRequestInternal> GetImageKnifeRequestInternal() const
    {
        return imageKnifeRequest_;
    }

    int GetNodeVersion() const
    {
        return componentVersion_;
    }

    ArkUI_NodeHandle GetHandle() const override
    {
        return handle;
    }

    NodeState GetNodeState() const
    {
        return nodeState_;
    }

    float GetWidth() const
    {
        return width_;
    }

    float GetHeight() const
    {
        return height_;
    }

    virtual void SetColorFilter(std::shared_ptr<ImageKnifeColorFilter> colorFilter)
    {
    }

    virtual void RemoveColorFilter()
    {
    }

    void SetWidth(float width) override;

    void SetHeight(float height) override;

    void SetPercentWidth(float width) override;

    void SetPercentHeight(float height) override;

    void SetMainSrcKey(std::string key);

    void SetContentSlot(ArkUI_NodeContentHandle contentSlot);

    std::string GetMainSrcKey() const;

    // 返回测算后的尺寸，单位px
    virtual Image_Size GetComponentSize();

    // 返回false需要立即解码svg
    bool IsDecodeSvgAfterMeasure(std::shared_ptr<ImageKnifeTaskInternal> task);
protected:
    // 测算结束后，可能有依赖组件测算宽高的svg图片需要发起解码
    void OnMeasureComplete();

    std::shared_ptr<BorderOption> GetComponentBorderOption() const
    {
        return border_;
    }

    bool UploadNodeHandle();
    bool IsAdaptable() const;
private:
    bool adaptable_ = false;
    bool customMeasure_ = false;
    bool nodeUploaded_ = false;
    ArkUI_NodeContentHandle contentSlot_ = nullptr;

    // 组件属性
    std::shared_ptr<BorderOption> border_ = nullptr;
    ArkUI_ObjectFit objectFit_ = ARKUI_OBJECT_FIT_CONTAIN;
    ArkUI_ObjectFit placeholderObjectFit_ = ARKUI_OBJECT_FIT_CONTAIN;
    ArkUI_ObjectFit thumbnailObjectFit_ = ARKUI_OBJECT_FIT_CONTAIN;
    ArkUI_ObjectFit errorObjectFit_ = ARKUI_OBJECT_FIT_CONTAIN;
    std::shared_ptr<ImageKnifeColorFilter> colorFilter_ = nullptr;
    std::shared_ptr<ResizableOption> resizeable_ = nullptr;

    // 主图key
    std::string mainSrcKey_;
    float width_ = 0;
    float height_ = 0;
    std::atomic<int> componentVersion_ = 0;
    NodeState nodeState_ = AVAILABLE;

    std::string componentId_;
    // 保持request生命周期
    std::shared_ptr<ImageKnifeRequestInternal> imageKnifeRequest_ = nullptr;

    // 测算相关
    std::mutex measureLock_;
    bool measureComplete_ = false;
    // 测算完成后需要发起svg解码的类型
    std::list<std::shared_ptr<ImageKnifeTaskInternal>> decodeSvgTasks_;
    void ReleaseDecodeSvgTasks();

    void Init(std::shared_ptr<ImageKnifeOption> option);

    virtual void RemoveDisplayedImage() = 0;

    bool IsUpdateNecessary(std::shared_ptr<ImageKnifeOption> option);

    static void OnNodeEvent(ArkUI_NodeEvent *event);
    
    virtual void OnNodeShow();
    virtual void OnNodeHide();
    void OnVisibleAreaChange(ArkUI_NodeEvent *event);
    void OnAreaChange(ArkUI_NodeEvent *event);

    virtual void OnDerivedNodeEvent(ArkUI_NodeEvent *event)
    {
    }

    virtual void UpdateDerivedNodeEvent(std::shared_ptr<ImageKnifeOption> option)
    {
    }

    virtual void RefreshImage()
    {
    }

    virtual void RefreshDrawing()
    {
    }

    virtual void SetResizeableOption(std::shared_ptr<ResizableOption> resizeable);
    virtual void RemoveResizeableOption();

    bool IsResizeableOptionChanged(std::shared_ptr<ImageKnifeOption> option);
    bool IsBorderChanged(std::shared_ptr<ImageKnifeOption> option);

    void SetBorder();

    void RemoveBorder();

    void UpdateAttribute(std::shared_ptr<ImageKnifeOption> option);

    template<typename T>
    bool CompareBorderProperty(std::vector<T> &data1, std::vector<T> &data2)
    {
        if (data1.empty() && data2.empty()) {
            return true;
        }
        if (data1.size() == 1 && data2.size() == 1) {
            return data1[0] == data2[0];
        }

        const int argSize = 4;
        if (data1.size() >= argSize && data2.size() >= argSize) {
            for (int i = 0; i < argSize; i++) {
                if (data1[i] != data2[i]) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    template<typename T>
    void SetBorderProperty(std::vector<T> &data, ArkUI_NodeAttributeType property)
    {
        if (data.empty()) {
            // 移除对应border属性
            GetNodeAPI()->resetAttribute(handle, property);
        } else {
            const int maxSize = 4;
            ArkUI_NumberValue numValue[maxSize];
            int32_t count = data.size() >= maxSize ? maxSize : 1;
            for (int i = 0; i < count; i++) {
                if constexpr (std::is_same<float, T>()) {
                    numValue[i].f32 = data[i];
                } else if constexpr (std::is_same<uint32_t, T>()) {
                    numValue[i].u32 = data[i];
                } else if constexpr (std::is_same<ArkUI_BorderStyle, T>()) {
                    numValue[i].i32 = static_cast<int32_t>(data[i]);
                } else {
                    IMAGE_KNIFE_LOG(LOG_ERROR, "SetBorder Property Wrong Format");
                    return;
                }
            }

            ArkUI_AttributeItem item = { .value = numValue, .size= count};
            GetNodeAPI()->setAttribute(handle, property, &item);
        }
    }
};

} // end of namespace

#endif // IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_NODE_INTERNAL_H